<template>
  <div class="small-widget" v-if="canvas">
    <ul class="controls">
      <li
        class="control"
        v-for="(item, index) in controls"
        :key="index"
        @click="item.handler"
        :class="{ disabled: zoomLevel === item.disabledValue }"
      >
        <el-icon v-if="item.icon">
          <Refresh v-if="item.icon === 'Refresh'"></Refresh>
          <ZoomIn v-else-if="item.icon === 'ZoomIn'"></ZoomIn>
          <ZoomOut v-else-if="item.icon === 'ZoomOut'"></ZoomOut>
        </el-icon>
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue'
import { useFabricStore } from '@/stores/fabric'
import { storeToRefs } from 'pinia'
import { ZoomIn, ZoomOut, Refresh } from '@element-plus/icons-vue'

const fabricStore = useFabricStore()
const { canvas, boardWidth, boardHeight } = storeToRefs(fabricStore)

const zoomLevel = ref(1)
const zoomStep = ref(0.2)
const maxZoomLevel = 5
const minZoomLevel = 0.2
const viewportTransformBackup = ref([])

const controls = ref([
  {
    icon: 'ZoomIn',
    disabledValue: maxZoomLevel,
    handler: () => {
      const zoom = canvas.value.getZoom()
      zoomLevel.value = zoom * (1 + zoomStep.value)
      if (zoomLevel.value > maxZoomLevel) {
        zoomLevel.value = maxZoomLevel
      }
      canvas.value.zoomToPoint(
        { x: canvas.value.getWidth() / 2, y: canvas.value.getHeight() / 2 },
        zoomLevel.value,
      )
      canvas.value.getActiveObject()?.setCoords()
    },
  },
  {
    icon: 'ZoomOut',
    disabledValue: minZoomLevel,
    handler: () => {
      const zoom = canvas.value.getZoom()
      zoomLevel.value = zoom * (1 - zoomStep.value)
      if (zoomLevel.value < minZoomLevel) {
        zoomLevel.value = minZoomLevel
      }
      canvas.value.setZoom(zoomLevel.value)
      const vpt = canvas.value.viewportTransform
      const width = canvas.value.getWidth()
      const height = canvas.value.getHeight()
      vpt[4] = width / 2 - (boardWidth.value * zoomLevel.value) / 2 //x轴偏移
      vpt[5] = height / 2 - (boardHeight.value * zoomLevel.value) / 2 //y轴偏移
      canvas.value.getActiveObject()?.setCoords()
    },
  },
  {
    icon: 'Refresh',
    handler: () => {
      canvas.value.setViewportTransform(viewportTransformBackup.value)
    },
  },
])

let mouseWheelCancer, mouseDownCancer, mouseMoveCancer, mouseUpCancer

watch(canvas, () => {
  viewportTransformBackup.value = canvas.value.viewportTransform
  // 缩放
  mouseWheelCancer = canvas.value.on('mouse:wheel', function ({ e }) {
    e.preventDefault()
    e.stopPropagation()
    if (!e.altKey) return
    const { deltaY } = e
    let zoom = canvas.value.getZoom()
    zoom *= 0.999 ** deltaY
    if (zoom > maxZoomLevel) zoom = maxZoomLevel
    if (zoom < minZoomLevel) zoom = minZoomLevel
    canvas.value.zoomToPoint({ x: e.offsetX, y: e.offsetY }, zoom)
    const vpt = canvas.value.viewportTransform
    const width = canvas.value.getWidth()
    const height = canvas.value.getHeight()
    if (zoom < width / boardWidth.value) {
      vpt[4] = width / 2 - (boardWidth.value * zoom) / 2
      vpt[5] = height / 2 - (boardHeight.value * zoom) / 2
    } else {
      if (vpt[4] >= 0) {
        vpt[4] = 0
      } else if (vpt[4] < width - boardWidth.value * zoom) {
        vpt[4] = width - boardWidth.value * zoom
      }
      if (vpt[5] >= 0) {
        vpt[5] = 0
      } else if (vpt[5] < height - boardHeight.value * zoom) {
        vpt[5] = height - boardHeight.value * zoom
      }
    }
    zoomLevel.value = zoom
    canvas.value.getActiveObject()?.setCoords()
  })
  // 平移
  mouseDownCancer = canvas.value.on('mouse:down', function ({ e }) {
    if (!e.altKey) return
    canvas.value.isDragging = true
    canvas.value.selection = false
    canvas.value.lastPosX = e.offsetX
    canvas.value.lastPosY = e.offsetY
  })
  mouseMoveCancer = canvas.value.on('mouse:move', function ({ e }) {
    if (!canvas.value.isDragging) return
    const zoom = canvas.value.getZoom()
    const vpt = canvas.value.viewportTransform
    const width = canvas.value.getWidth()
    const height = canvas.value.getHeight()
    if (zoom < width / boardWidth.value) {
      vpt[4] = width / 2 - (boardWidth.value * zoom) / 2
      vpt[5] = height / 2 - (boardHeight.value * zoom) / 2
    } else {
      vpt[4] += e.offsetX - canvas.value.lastPosX
      vpt[5] += e.offsetY - canvas.value.lastPosY
      if (vpt[4] >= 0) {
        vpt[4] = 0
      } else if (vpt[4] < width - boardWidth.value * zoom) {
        vpt[4] = width - boardWidth.value * zoom
      }
      if (vpt[5] >= 0) {
        vpt[5] = 0
      } else if (vpt[5] < height - boardHeight.value * zoom) {
        vpt[5] = height - boardHeight.value * zoom
      }
    }
    canvas.value.requestRenderAll()
    canvas.value.lastPosX = e.offsetX
    canvas.value.lastPosY = e.offsetY
  })
  mouseUpCancer = canvas.value.on('mouse:up', function ({ e }) {
    canvas.value.setViewportTransform(canvas.value.viewportTransform)
    canvas.value.isDragging = false
    canvas.value.selection = true
  })
})
</script>

<style lang="scss" scoped>
.small-widget {
  position: absolute;
  right: 5.5rem;
  bottom: 5rem;
  .controls {
    display: flex;
    flex-direction: column;
    color: #ddd;
    border-radius: 3px;
    .control {
      width: 2rem;
      height: 2rem;
      background-color: #001245;
      border: 1px solid rgba(221, 221, 221, 0.5);
      border-width: 1px 1px 0 1px;
      text-align: center;
      align-content: center;
      overflow: hidden;
      cursor: pointer;

      &:first-child {
        border-radius: 3px 3px 0 0;
      }
      &:last-child {
        border-bottom: 1px solid rgba(221, 221, 221, 0.5);
        border-radius: 0 0 3px 3px;
      }
      &.disabled {
        cursor: not-allowed;
      }
      &:not(.disabled) {
        &:hover {
          color: #409eff;
          border-color: rgba(64, 158, 255, 0.5);
          .el-icon {
            transform: scale(1.1);
          }
        }
      }
    }
  }
}
</style>
